{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Unsupervised Machine learning using arcgis.learn guide"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Table of Contents\n",
    "* [Introduction](#Introduction) \n",
    "* [Prepare tabular data](#Prepare-tabular-data)  \n",
    "* [Data Visualization](#Data-Visualization)\n",
    "* [Load Unsupervised model architecture](#Load-Unsupervised-model-architecture)\n",
    "    * [Finding Number of Clusters](#Finding-Number-of-Clusters) \n",
    "* [Unsupervised ML Model Training](#Unsupervised-ML-Model-Training)\n",
    "* [Model Validation metrics](#Model-Validation-metrics)\n",
    "* [Model Saving & Loading](#Model-Saving-&-Loading)\n",
    "* [Model Inferencing](#Model-Inferencing]) \n",
    "* [Summary](#Summary)\n",
    "* [References](#References)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the unsupervised section of the [MLModel](https://developers.arcgis.com/python/api-reference/arcgis.learn.toc.html#mlmodel) implementation available in `arcgis.learn`, selected [scikit-learn unsupervised](https://scikit-learn.org/stable/unsupervised_learning.html) model could be fitted using this framework. The unsupervised modules that can be used from scikit-learn includes [Gaussian mixture models](https://scikit-learn.org/stable/modules/mixture.html), [Clustering algorithms](https://scikit-learn.org/stable/modules/clustering.html) and [Novelty and Outlier Detection](https://scikit-learn.org/stable/modules/outlier_detection.html). Unsupervised learning as the name suggest does not require labelled data and is also regarded by many as the true form of AI. Thus, compared to supervised machine learning, unsupervised learning discovers existing patterns in the input data by itself."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Data can be [feature layer](https://developers.arcgis.com/python/guide/working-with-feature-layers-and-features/), [spatially enabled dataframe](https://developers.arcgis.com/python/guide/introduction-to-the-spatially-enabled-dataframe/) with/without rasters or just a simple dataframe. Usually in case of unsupervised learning there is no dependent variable and the explanatory variables can take the form of fields in the attribute table of the training features, raster datasets, and distance features used to calculate proximity values for use as additional variables. In addition to validation of model performance based on the training data, predictions can be made to produce either features or a prediction raster.  Training and predictions can be performed for both categorical variables and continuous variables.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "The overall implementation methodology of the unsupervised machine learning is identical to that of supervised machine learning, but only with additional respective functionalities for the various modules and their submodules, which are discussed in the following available unsupervised scikit-learn models:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1.  Gaussian Mixture Models\n",
    "    * <td><a href=\"https://scikit-learn.org/stable/modules/mixture.html\"><p align=\"left\">Gaussian Mixture Models</p></a></td>\n",
    "2.  Clustering\n",
    "    * <td><a href=\"https://scikit-learn.org/stable/modules/clustering.html#k-means\"><p align=\"left\">K-means</p></a></td>\n",
    "3.  Novelty and Outlier Detection\n",
    "    * <td><a href=\"https://scikit-learn.org/stable/modules/outlier_detection.html#novelty-detection\"><p align=\"left\">Novelty Detection</p></a></td>\n",
    "    * <td><a href=\"https://scikit-learn.org/stable/modules/outlier_detection.html#id1\"><p align=\"left\">Outlier Detection</p></a></td>\n",
    "    * <td><a href=\"https://scikit-learn.org/stable/modules/outlier_detection.html#novelty-detection-with-local-outlier-factor\"><p align=\"left\">Novelty Detection with Local Outlier Factor</p></a></td>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prepare tabular data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first step is to create a TabularDataObject using the `prepare_tabulardata` method that can be fed into the various unsupervised `MLModel` models. This data preparation is carried out using the attribute data from feature layers, spatial data frames. Additionally, variables in the form of rasters can be used. The raster dataset can be imagery layer which can be accessed through ArcGIS portal or locally saved rasters which can be accessed using the raster class from ArcGIS API for Python. This method performs normalization of the datasets, imputation, and splits it into training and validation datasets before feeding the datasets into the model.\n",
    "\n",
    "The `prepare_tabulardata` method inspects the type of fields in the input data and automatically treats them as continuous variables. However, for categorical variables a `True` value has to be passed inside a tuple along with the specific variable.\n",
    "\n",
    "As part of the input data, the explanatory variables containing categorical and continuous variables are defined as follows:\n",
    "\n",
    "`X = [\"Field_1\", (\"Field_2\", True),.......\"Field_n\"]`\n",
    "\n",
    "Here **Field_2** is treated as categorical and the others as continuous variables.\n",
    "\n",
    "In cases where variables are stored as multiple rasters, then:\n",
    "\n",
    "`explanatory_rasters = [RasterClassObject1,(RasterClassObject2, True),.......RasterClassObjectn]` \n",
    "\n",
    "\n",
    "Here, RasterClassObject2 is treated as categorical and the others as continuous variables."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`preprocessors`: Finally data transformation information is stored in the `preprocessors` parameter.  With this the user can select any scaler function from scikit-learn to transform the fields using the selected scaler as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocessors = [('column1','column2',scaler1),('column1', Scalar2),.....]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and as well scale the full dataset instead of individual columns using a single scaler:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocessors =  [(\"Field_1\", (\"Field_2\", True),.......\"Field_n\", MinMaxScaler())]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The follows scale the whole dataset:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocessors = [(*df.columns,scaler)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the dataset is a raster the preprocessors can be defined as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocessors = [('raster.tif',MinMaxScaler())]  # also the following"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocessors = [(raster.name, MinMaxScaler())] # here raster is the Raster object"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here these variables are transformed by the MinMaxScaler function by passing it, along with the variable list as the last item. The user can choose any scaler function for the same. If nothing is passed, then the default is Normalizer from scikit learn. The MinMaxScaler is imported from scikit-learn as the scaling function. The scikit-learn module is packaged into the ArcGis learn module, and no separate installation of scikit-learn is not required."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once the explanatory variables or the explanatory rasters list is ready, these can now be used as input for the prepare_tabulardata() method. The method takes the feature layer or a spatial dataframe containing the dataset along with the `explanatory_variables` and `preprocessors` and prepares it for fitting the selected unsupervised model form scikit-learn as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = prepare_tabulardata(input_feature,                             \n",
    "                            explanatory_variables=X,\n",
    "                            explanatory_rasters=[explanatory_rasters],\n",
    "                            preprocessors=preprocessors)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In case the input dataset are only rasters, then `explanatory_variables=X` is ignored in the above "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here: \n",
    "\n",
    "`input_features`: It takes in data in the form of feature layer, spatially enabled data frames, or simple dataframe. Feature layers can be of point or polygon geometry.\n",
    "\n",
    "`date_field`: Field name from the input_features layer. If specified, the field will be split into year, month, week, day, dayofweek, dayofyear, is_month_end, is_month_start, is_quarter_end, is_quarter_start, is_year_end, is_year_start, hour, minute, second, elapsed. If specified here, there is no need to specify as part of explanatory_variables in the following.\n",
    "\n",
    "`explanatory_variables` : List of the field names containing the explanatory variables from the input_layer, where 2-sized tuples has to be passed for categorical variables as discussed above.\n",
    "\n",
    "`explanatory_rasters` : List of the Raster objects, where 2-sized tuples has to be passed for categorical variables as discussed above.\n",
    "\n",
    "`distance_features`: Distance features are used to automatically create explanatory variables by calculating a distance from the provided features to the input_features. Distances will be calculated from each of the input explanatory distance features to the nearest Input training features. If the input distance_features are polygons or lines, the distance attributes are calculated as the distance between the closest segments of the pair of features. However, distances are calculated differently for polygons and lines. See how proximity tools calculate distance for details.\n",
    "\n",
    "`preprocessors`: Data transformation is accomplished by the `preprocessors` parameter."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Visualization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Data visualization can provide useful information for modeling, for example it  can show missing data, data trends, existing correlation among predictors and with the dependent variable, variable significance and redundancy etc., which will help determine the  significant parameter for modeling initialization.\n",
    "\n",
    "This visualization is done by `data.show_batch(rows=n)` which will print out n random rows of the original data. The entire data can be printed using `data._dataframe` "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load Unsupervised model architecture"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The TabularDataObject prepared by the `prepare_tabulardata` method is now ready to be passed to the `MLModel` method for model initialization. A selected unsupervised machine learning model from scikit-learn is used for loading the model for training. Here, for demonstration purpose, model initialization with some sample unsupervised model from scikit-learn is shown, which is passed into the `MLModel` function, along with its parameters.\n",
    "\n",
    "First, the `MLModel` is imported from `arcgis.learn`. Then, the model to be used from scikit-learn is specified with the respective model parameters defined as keyword arguements:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from arcgis.learn import MLModel"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html\">Gaussian Mixture Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the unsupervised mlmodel with a Gaussian mixture model along with the parameters  \n",
    "model = MLModel(data, 'sklearn.mixture.GaussianMixture',\n",
    "                n_components=3,\n",
    "                covariance_type='spherical', \n",
    "                n_init=10,\n",
    "                tol=1e-3,\n",
    "                max_iter=1000,\n",
    "                random_state=42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html\">K-means Clustering Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the unsupervised mlmodel with a kmeans clustering model along with the parameters \n",
    "model = MLModel(data, 'sklearn.cluster.KMeans',\n",
    "                n_clusters=3,\n",
    "                init='k-means++',\n",
    "                random_state=43)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Finding Number of Clusters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above model initialization if the number of components(n_components) for the Gaussian Mixture Model, and number of clusters(n_clusters) for the K-means clustering Model are not passed it automatically finds the optimum number of clusters for the respective unsupervised scikit-learn models using the [Silhouette analysis](https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html), and bic score respectively."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample Anomaly detection <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\">Isolation Forest Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the mlmodel with unsupervised anomaly detection Isolation forest model along with the parameters\n",
    "outliers_fraction = .04\n",
    "model = MLModel(data, 'sklearn.ensemble.IsolationForest',\n",
    "                n_estimators=10,\n",
    "                contamination=outliers_fraction,\n",
    "                random_state=42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample Outlier detection <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.covariance.EllipticEnvelope.html#sklearn.covariance.EllipticEnvelope\">Elliptic Envelope Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the mlmodel with a unsupervised Outlier Detection Elliptic Envelope model along with the parameters\n",
    "outliers_fraction = .04\n",
    "model = MLModel(data, 'sklearn.covariance.EllipticEnvelope',\n",
    "                contamination=outliers_fraction,\n",
    "                random_state=42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample Unsupervised Novelty detection <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.LocalOutlierFactor.html#sklearn.neighbors.LocalOutlierFactor\">Local Outlier Factor (LOF) Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the mlmodel with a unsupervised novelty detection Local Outlier Factor model along with the parameters\n",
    "# for using LOF as a outllier detection model the estimator can be instantiated with the novelty parameter set to False\n",
    "outliers_fraction = .04\n",
    "model = MLModel(data, 'sklearn.neighbors.LocalOutlierFactor',\n",
    "                n_neighbors=20,\n",
    "                novelty=True,\n",
    "                contamination=outliers_fraction)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### <td> Initialization of a sample Unsupervised Outlier and Novelty detection using <a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.svm.OneClassSVM.html\">One-Class SVM Model</a></td>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# defining the mlmodel with a unsupervised novelty detection Local Outlier Factor model along with the parameters\n",
    "outliers_fraction = .04\n",
    "model = MLModel(data, 'sklearn.svm.OneClassSVM',\n",
    "                nu=outliers_fraction,\n",
    "                kernel=\"rbf\", gamma=0.1) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unsupervised ML Model Training\n",
    "Once the machine learning model is initialized with the data, the unsupervised scikit-learn model and its parameters mentioned in the previous step, the `model.fit()` method is used for fitting the machine learning model. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.fit()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After the model is trained, sample results of the the training are printed using `model.show_results(rows=n)`. The model.show_results() will typically output a table where the last column will contain the values or the labels predicted by the model on the trained dataset. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Validation metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Unlike supervised MLModel there is no universal model scoring method for determining model performances for unsupervised MLModels, since there are no labels to measure the success of trained model. Thus, unsupervised modeling is extremely flexible, which finds existing patterns in the data which are unknown to the user, rather than predefined labels to guide the optimization process.      \n",
    "\n",
    "However, the results returned by the trained unsupervised models has respective indexes to understand the quality of results. Some of these functions for the respective unsupervised scikti-learn model available via the MLModel implementation are as follows:   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html\">Gaussian Mixture Model</a></span> \n",
    "\n",
    "`predict_probability(X)` method predict posterior probability of each component given the data, thereby give probability of each sample for belonging to a certain cluster for Gaussian mixture modeling.\n",
    "\n",
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html\">K-means Clustering Model</a></span>\n",
    "\n",
    "`score(X, y=None, sample_weight=None)` function returns the opposite of inertia of the fit model, hence the greater the value better is the clustering or lowest inertia returns the best clusters.\n",
    "\n",
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\">Isolation Forest Model</a></span>\n",
    "\n",
    "`decision_function(X)` returns average anomaly score of X of the base classifiers. The anomaly score of an input sample is computed as the mean anomaly score of the trees in the forest. This function other than identifying anomaly could also be used understanding  explainability  of predictors causing the anomaly, and as well selecting anomlay based on upper and lower bound quantile.\n",
    "\n",
    "\n",
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.svm.OneClassSVM.html\">One-Class SVM Model</a></span>\n",
    "\n",
    "`decision_function(X)` Signed distance to the separating hyperplane. Signed distance is positive for an inlier and negative for an outlier.\n",
    "\n",
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.LocalOutlierFactor.html#sklearn.neighbors.LocalOutlierFactor\">Local Outlier Factor (LOF) Model</a></span>\n",
    "\n",
    "\n",
    "`kneighbors(X=None, n_neighbors=None, return_distance=True)` function finds the K-neighbors of a point, and returns indices of and distances to the neighbors of each point. Using the estimated distance for each sample point it decides the anomaly samples. This is a density-based outliers detection method, based on the its distance from surrounding neighbours, compared to other points & distance of their neighbors.\n",
    "\n",
    "<span style='color:Gray'><a href=\"https://scikit-learn.org/stable/modules/generated/sklearn.covariance.EllipticEnvelope.html#sklearn.covariance.EllipticEnvelope\">Elliptic Envelope Model</a></span>\n",
    "\n",
    "`mahalanobis(X)` function computes the squared Mahalanobis distances of given observations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Saving & Loading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The trained model can now be saved using the model.save(name_or_path) command, which will save the model weights and create an Esri Model Definition and Deep Learning Package or DLPK zip. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save(r'/path/', publish=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `publish` parameter is an optional boolean which publishes the DLPK as an item in Arcgis portal.\n",
    "\n",
    "The saved model can be loaded back using `model.from_model(emd_path, data=None)`, which will load the trained model from the provided `emd_path` and would be ready for inferencing. The `data` parameter is optional and requires a fastai Databunch returned  by the `prepare_tabulardata` function, and is only for further training the model on a new dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Inferencing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Predicting to features`\n",
    "\n",
    "With a model that has been trained using any combination of `Explanatory Variables`, `distance Features`, and `Explanatory Training Rasters`, it can be used to predict clusters, labels or anomaly on the same dataset that it has been trained. Predicting to features option is provided by default in the `prediction_type` , where it publishes the resulting layer with the provided name in the output_layer_name  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pred = model.predict(feature_data_layer, output_layer_name='prediction_clusters')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Predicting to dataframe`\n",
    "\n",
    "The user can predict it to a resulting dataframe by mentioning in the `prediction_type` as `dataframe`, which can be saved locally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pred_new = model.predict(feature_data_layer, prediction_type='dataframe')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Predicting to rasters`\n",
    "The user can predict it to a raster data type by mentioning the `prediction_type` as raster and providing a path for the  output_raster_path, for saving it locally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pred_new = model.predict(explanatory_rasters=[raster1], \n",
    "                         prediction_type='raster',\n",
    "                         output_raster_path=r\"\\folder_path\\result.tif\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here in this guide application of selected unsupervised models via the MLModel framework was elaborated. The scikit-learn models that could be applied using this framework are Gaussian mixture models, Clustering algorithms and Novelty and Outlier Detection also Anomaly detection models from scikit-learn.\n",
    "\n",
    "An important implementation for the gaussian mixture models and clustering algorithm of automatically finding the optimum number of clusters were shown, which can provide interesting insight to discover data patterns.\n",
    "\n",
    "Application of these models can be better understood from various sample notebooks for example the one where deforested areas are identified using a gaussian mixture model, which would be made available in this repository for GIS analysts and data scientists, along with other interesting notebooks that are planned using this module from ArcGIS API for Python."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Topic | Description | Link |\n",
    "| -| - |-|\n",
    "| MLModel| MLModel from arcgis.learn module  |https://developers.arcgis.com/python/api-reference/arcgis.learn.toc.html#mlmodel|\n",
    "| scikit-learn unsupervised models| Unsupervised models implemented from scikit learn  |https://scikit-learn.org/stable/unsupervised_learning.html|\n",
    "| Gaussian mixture model| Gaussian mixture model from scikit learn  |https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html|\n",
    "| Clustering algorithm| Clustering models from scikit learn  |https://scikit-learn.org/stable/modules/clustering.html|\n",
    "| K-means Clustering| K-means clustering model   |https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html|\n",
    "| Silhouette analysis| Silhouette analysis for optimizing clusters  |https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html|\n",
    "| One-Class SVM model| Novelty and Outlier Detection models|https://scikit-learn.org/stable/modules/generated/sklearn.svm.OneClassSVM.html|\n",
    "| Local Outlier Factor (LOF) model| Novelty detection model|https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.LocalOutlierFactor.html#sklearn.neighbors.LocalOutlierFactor|\n",
    "| Elliptic Envelope Model| Outlier detection model  |https://scikit-learn.org/stable/modules/generated/sklearn.covariance.EllipticEnvelope.html#sklearn.covariance.EllipticEnvelope|\n",
    "| IsolationForest Model| Anomaly detection  |https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html|\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
